#!/usr/bin/python2.6

from text2int import text2int as t2i
import sys

class OptionError(Exception):
    pass

class optionClass:
    '''A small class for keeping track of setting and retrieving options.  Supports setting up a limited set of values for a given option.'''

    def __init__(self, infunc = raw_input, 
                 outfunc = lambda x,y: sys.stdout.write(x), 
                 **kwargs):

        '''working'''
        #Defaults
        self.optionVals = {}
        self.defaults = {}
        self.possibleValues = {}
        self.valTypes = {}
        self.prompts = {}
        self.infunc = infunc
        self.outfunc = outfunc

        if kwargs.get('defaults', False):
            for opt in kwargs['defaults'].keys():
                self.defaults[opt] = kwargs['defaults'][opt]
                self.optionVals[opt] = kwargs['defaults'][opt]

        if kwargs.get('optionVals', False):
            for opt in kwargs['optionVals'].keys():
                self.optionVals[opt] = kwargs['optionVals'][opt]

        if kwargs.get('possible', False):
            for opt in kwargs['possible'].keys():
                self.possibleValues[opt] = kwargs['possible'][opt]

        if kwargs.get('types', False):
            for opt in kwargs['types'].keys():
                self.valTypes[opt] = kwargs['types'].get(opt, None)

        if kwargs.get('prompts', False):
            for opt in kwargs['prompts'].keys():
                self.prompts[opt] = kwargs['prompts'].get(opt, None)

 
    def addOption(self, optionName, **kwargs):
        '''working'''
        if optionName in self.optionVals.keys():
            raise ValueError("Option already exists")

        self.optionVals[optionName] = None

        if kwargs.get('default', False):
            self.defaults[optionName] = kwargs['default']

        if kwargs.get('possible', False):
            self.possibleValues[optionName] = kwargs['possible']
            
        if kwargs.get('value', False):
            self[optionName] = kwargs['value']
        else:
            self[optionName] = kwargs['default']

        if kwargs.get('prompt', False):
            self.prompts[optionName] = kwargs['prompt']

        
    def setOption(self, optionName, value):
        self[optionName] = value

    def optionHelp(self, words):
        words.pop(0)

        for word in words:
            if word in self.prompts.keys():
                self.outfunc(word + ": " + self.prompts[word])
                self.outfunc("Possible values are: " + str(self.possible[word]))

        if len(words) == 0:
            outfunc("Say \"set\" to set an option value.   Say \"Default\" to reset an option to its default value.  Any of these commands may be followed by the option name and new value.")

    def optionMenu(self):
        '''Working'''
        menuFuncs = {'set' : self.setOptionMenu,
                     'default' : self.setOptionToDefault,
                     'help' : self.optionHelp}
        

        while True:
            self.outfunc("Which option would you like to set?", self)
            self.outfunc("Say quit to exit menu", self)
            self.printOpts()
            try:
                instr = self.infunc()
            except EOFError:
                break
            
            if instr in ['q', 'quit', 'done', 'exit', 'x', 'bye']:
                return

            words = instr.split()

            if words[0] in menuFuncs.keys():
                menuFuncs[words[0]](words)
            else:
                self.outfunc("Unknown option: " + words[0] + '\n', self)
           

    def setOptionMenu(self, words):
        '''working'''
        optionName = words[1]
        if not optionName in self.keys():
            self.outfunc("Invalid option", self)

        if len(words) > 2:
            newval = ' '.join(words[2:])
            try:
                self[optionName] = newval
            except ValueError:
                self.outfunc("Invalid option value", self)
            except OptionError:
                self.outfunc("Invalid option", self)

        else:
            if self.prompts.get(optionName, False):
                prompt = self.prompts.get(optionName, False)
            else:
                prompt = ""

            self.outfunc(optionName + ": " + prompt, self)
            inval = self.infunc("Enter new value: ")
            try:
                self[optionName] = inval
            except ValueError:
                self.outfunc("Invalid option value", self)


    def setOptionToDefault(self, words):
        '''working'''
        optionName = words[1]
        defVal = self.defaults[optionName]
        self.outfunc("Setting " + optionName + " to default value: " + str(defVal), self)
        self[optionName] = defVal


    def printOpts(self):
        '''working'''
        self.outfunc(self.__str__(), self)

    def __str__(self):
        '''Print options and values in a nice sorted way'''
        strOut = ''
        for opt in sorted(self.keys()):
            strOut += opt + ": " + str(self[opt]) + ' \n'
        return strOut

    def __getitem__(self, optionName):
        '''working'''
        return self.optionVals[optionName]

    def get(self, optionName, default = None):
        '''working'''
        return self.optionVals.get(optionName, default)

    def __setitem__(self, optionName, value):
        '''Working'''
        if not optionName in self.keys():
            raise OptionError("Invalid Option")

        optType = self.valTypes.get(optionName, None)

        if not optType == None:
            
            try:
                value = optType(value)
            except:
                badTypeFound = True
                if optType == int:
                    try:
                        value = t2i(value)
                    except:
                        badTypeFound = True
                    else:
                        badTypeFound = False

                if badTypeFound:
                    badtype = str(type(value))[7:-2]
                    goodtype = str(optType)[7:-2]
                    self.outfunc("Invalid option type: " + badtype, self)
                    self.outfunc("Use type: " + goodtype, self)
                    return

        possibleVals = self.possibleValues.get(optionName, [])
        if possibleVals:
            if not value in possibleVals:
                raise ValueError("Option value not allowed")
        self.optionVals[optionName] = value
        #self.setOption(optionName, value)

    def keys(self):
        '''working'''
        return self.optionVals.keys()

    def values(self):
        '''working'''
        return self.optionVals.values()

    def items(self):
        '''working'''
        return self.optionVals.items()

    


def main():
    vals = {'size' : 'large', 'sex' : 'yes', 'times' : 3}
    d = {'size' : 'small', 'sex' : 'yes', 'times' : None, 'door' : 'closed'}
    poss = {'size' : ['small', 'med', 'large'],
            'sex' : ['yes', 'no', 'maybe later'],
            'times' : range(10),
            'door' : ['open', 'closed']}
    t = {'size' : str, 'sex' : str, 'times' : int}
    p = {'size' : "How big?", 'sex' : "How many sex would you like?",
         'times' : "How many times?", 'door' : "Open or closed?"}

    o = optionClass(infunc = raw_input,
                    outfunc = sys.stdout.write,
                    defaults = d, 
                    optionVals = vals, 
                    prompts = p,
                    possible = poss, types = t)
   
    #o.outfunc(o.items(), self)
    o.addOption('color', default = 'red', 
                possible = ['red', 'white', 'blue'], value = 'white', 
                prompt = "What is your favorite color?")

    #o.outfunc(o.items(), self)

    print o.get('sex')
    print o.get('pizza')

    #o.optionMenu()

if __name__ == '__main__':
    main()
